/*============================= Controller.m ================================*/
/* Class controls a demo panel. The panel shows one geographic coordinate
   in World Coordinates and various local UTM grid systems. It allows up to
   10 such points to be selected and edited.

HISTORY
7-Feb-93  Dale Amon at GPL
	  Created
*/

#import "Controller.h"
#import <misckit/miscgiskit.h>

#define MAXPOINTS	10

@implementation Controller

/*===========================================================================*/
/* Internal methods */
/*===========================================================================*/

- initTheInputMatrix: aTextMatrix
  {	id	east, north;
	east =  [aTextMatrix findCellWithTag: EASTING];
	north = [aTextMatrix findCellWithTag: NORTHING];

	[east setEntryType:NX_DOUBLETYPE];
	[east setFloatingPointFormat: NO
				left: METERS_DIGITS
			       right: METER_FRACTION_DIGITS];

	[north setEntryType:NX_DOUBLETYPE];
	[north setFloatingPointFormat: NO
				 left: METERS_DIGITS
				right: METER_FRACTION_DIGITS];
	return self;
  }


- outputWorldCoord: aWorldCoord inMatrix: aTextMatrix
  {	double	deg1,min1,sec1;
	double	deg2,min2,sec2;

	/* Load latitude as deg:min:sec. If value is negative, ie South,
	   display negative only on degrees field. */
	[MiscCoord fromDegreesOnly: [aWorldCoord latitudeDegrees]
		       degrees: &deg1 minutes: &min1 seconds: &sec1];
	if (sec1 < 0.0)    sec1 = -sec1;
	if (min1 < 0.0)    min1 = -min1;
	if (sec1 < .00001) sec1 = 0.0;

	[[aTextMatrix findCellWithTag:LATITUDE_DEGREES] setDoubleValue: deg1]; 
	[[aTextMatrix findCellWithTag:LATITUDE_MINUTES] setDoubleValue: min1]; 
	[[aTextMatrix findCellWithTag:LATITUDE_SECONDS] setDoubleValue: sec1]; 

	/* Load longitude as deg:min:sec If value is negative, ie East,
	   display negative only on degrees field. */
	[MiscCoord fromDegreesOnly: [aWorldCoord longitudeDegrees]
		       degrees: &deg2 minutes: &min2 seconds: &sec2];
	if (sec2 < 0.0)    sec2 = -sec2;
	if (min2 < 0.0)    min2 = -min2;
	if (sec2 < .00001) sec2 = 0.0;

	[[aTextMatrix findCellWithTag:LONGITUDE_DEGREES] setDoubleValue: deg2]; 
	[[aTextMatrix findCellWithTag:LONGITUDE_MINUTES] setDoubleValue: min2]; 
	[[aTextMatrix findCellWithTag:LONGITUDE_SECONDS] setDoubleValue: sec2]; 
	return self;
   }


- inputWorldCoord: aWorldCoord inMatrix: aTextMatrix
 {	double	deg,min,sec;
	double latitude,longitude;

	/* Only allow a minus sign in the degree field. A minus there makes
	   this an South Latitude */
	deg = [[aTextMatrix findCellWithTag:LATITUDE_DEGREES] doubleValue];
	min = [[aTextMatrix findCellWithTag:LATITUDE_MINUTES] doubleValue];
	sec = [[aTextMatrix findCellWithTag:LATITUDE_SECONDS] doubleValue];
	if (sec <0.0)  sec = -sec;
	if (min <0.0)  min = -min;
	if (deg <0.0) {min = -min; sec = -sec;}

	latitude = [MiscCoord toDegreesOnlyDegrees: deg
				       minutes: min
				       seconds: sec];

	/* Only allow a minus sign in the degree field. A minus there makes
	   this a West Longitude */
	deg = [[aTextMatrix findCellWithTag:LONGITUDE_DEGREES] doubleValue];
	min = [[aTextMatrix findCellWithTag:LONGITUDE_MINUTES] doubleValue];
	sec = [[aTextMatrix findCellWithTag:LONGITUDE_SECONDS] doubleValue];
	if (sec <0.0)  sec = -sec;
	if (min <0.0)  min = -min;
	if (deg <0.0) {min = -min; sec = -sec;}

	longitude = [MiscCoord toDegreesOnlyDegrees: deg
				        minutes: min
				        seconds: sec];

	[aWorldCoord setCoordLatitudeDegrees: latitude
        		   longitudeDegrees: longitude
				   altitude: 0.0];
	return self;
  }


- outputGridCoord: aGridCoord inMatrix: aTextMatrix
  {
	[[aTextMatrix findCellWithTag:EASTING]
		setDoubleValue: [aGridCoord easting]];
	[[aTextMatrix findCellWithTag:NORTHING]
		setDoubleValue: [aGridCoord northing]];

	return self;
   }

- inputGridCoord: aUTMCoord inMatrix: aTextMatrix
  {	double	easting, northing;
 
	easting =  [[aTextMatrix findCellWithTag:EASTING ] doubleValue];
	northing = [[aTextMatrix findCellWithTag:NORTHING] doubleValue];

	[aUTMCoord setCoordEastingMeters: easting
			  northingMeters: northing
			 elevationMeters: 0.0];
	return self;
  }


- recalcGridCoord: aCoord toMatrix: aMatrix
  {
	[worldCoord convert: aCoord];
	[self outputGridCoord: aCoord inMatrix: aMatrix];
	return self;
  }

- selectGridPnt: (unsigned int) n coord: aCoord toMatrix: aMatrix
  {
	[aCoord selectExistingPoints: n blockSize:1];
	[self outputGridCoord: aCoord inMatrix: aMatrix];
	return self;
  }


/*===========================================================================*/
/* When the Application starts, we are notified and carry out the required
   initialization. 
*/

- appDidInit:sender
{
	autoLaunch    = NXGetDefaultValue([NXApp appName], "NXAutoLaunch");

	[self initTheInputMatrix: ukngInput];
	[self initTheInputMatrix: ukz30Input];
	[self initTheInputMatrix: ukz31Input];
	[self initTheInputMatrix: igInput];
	[self initTheInputMatrix: igOldInput];

	[index setEntryType: NX_POSINTTYPE];
	[index setIntValue: 1];

	/* UK Grid origin */
	ukngCoord = [[MiscUKUTMCoord alloc] initDescription: "A UK point"];
	[ukngCoord selectAndSetMinPoints: 0 blockSize: MAXPOINTS];

	/* UK Zone 30 Grid origin */
	ukz30Coord = [[MiscZoneUTMCoord alloc]
			initDescription: "A UK Zone 30 point" zone: 30];
	[ukz30Coord selectAndSetMinPoints: 0 blockSize: MAXPOINTS];

	/* UK Zone 31 Grid origin */
	ukz31Coord = [[MiscZoneUTMCoord alloc]
			initDescription: "A UK Zone 31 point" zone: 31];
	[ukz31Coord selectAndSetMinPoints: 0 blockSize: MAXPOINTS];

	/* Irish Grid origin */
	igCoord = [[MiscIrelandUTMCoord alloc]
				 initDescription: "An Irish Grid point"];
	[igCoord selectAndSetMinPoints: 0 blockSize: MAXPOINTS];

	/* Old Irish Grid */
	igOldCoord = [[MiscIrelandOldUTMCoord alloc] initDescription:
						    "An Old Irish Grid point"];
	[igOldCoord selectAndSetMinPoints: 0 blockSize: MAXPOINTS];

	/* init test point to Greenwich */
	worldCoord = [[MiscWorldCoord alloc] initDescription: "A World Coord Point"
       					       constants: nil];
	[worldCoord selectAndSetMinPoints: 0 blockSize: MAXPOINTS];

	/* Set the world coord and then make all the grid cells update
	   to match the initial value */
	[worldCoord setCoordLatitudeDegrees: 49.0
			   longitudeDegrees: -2.0
				   altitude: 0.0];

	/* Set all the points to the same block size so the
	   convert method will succeed. */
	[self indexChanged: self];

	/* Then update them */
	[self outputWorldCoord: worldCoord inMatrix: worldInput];
	[self worldChanged: self];

	return self;
}


- indexChanged: sender
  {	unsigned int n;

	n = (unsigned int) [index intValue] - 1;
	if (![worldCoord selectExistingPoints: n blockSize:1])
		{[index setIntValue: (int) [worldCoord curIndex] + 1];
		 return self;
		}

	[self outputWorldCoord: worldCoord inMatrix: worldInput];

	[self selectGridPnt: n coord: ukngCoord  toMatrix: ukngInput];
	[self selectGridPnt: n coord: ukz30Coord toMatrix: ukz30Input];
	[self selectGridPnt: n coord: ukz31Coord toMatrix: ukz31Input];
	[self selectGridPnt: n coord: igCoord    toMatrix: igInput];
	[self selectGridPnt: n coord: igOldCoord toMatrix: igOldInput];
	return self;
  }

- worldChanged:sender
{
	/* read the new value */
	[self inputWorldCoord: worldCoord inMatrix: worldInput];

	/* Make sure the input fields are always in a standard format */
	[self outputWorldCoord: worldCoord inMatrix: worldInput];

	/* update all the grid displays to match the new world Coord */
	[self recalcGridCoord: ukngCoord  toMatrix: ukngInput];
	[self recalcGridCoord: ukz30Coord toMatrix: ukz30Input];
	[self recalcGridCoord: ukz31Coord toMatrix: ukz31Input];
	[self recalcGridCoord: igCoord    toMatrix: igInput];
	[self recalcGridCoord: igOldCoord toMatrix: igOldInput];

	return self;
}


- ukngChanged:sender
{
	/* read the new value */
	[self inputGridCoord: ukngCoord inMatrix: ukngInput];

	[ukngCoord convert: worldCoord];
	[self outputWorldCoord: worldCoord inMatrix: worldInput];

	/* update all the grid displays to match the new world Coord */
	[self recalcGridCoord: ukz30Coord toMatrix: ukz30Input];
	[self recalcGridCoord: ukz31Coord toMatrix: ukz31Input];
	[self recalcGridCoord: igCoord    toMatrix: igInput];
	[self recalcGridCoord: igOldCoord toMatrix: igOldInput];

	return self;
   }

- ukz30Changed:sender
{
	/* read the new value */
	[self inputGridCoord: ukz30Coord inMatrix: ukz30Input];

	[ukz30Coord convert: worldCoord];
	[self outputWorldCoord: worldCoord inMatrix: worldInput];

	/* update all the grid displays to match the new world Coord */
	[self recalcGridCoord: ukngCoord  toMatrix: ukngInput];
	[self recalcGridCoord: ukz31Coord toMatrix: ukz31Input];
	[self recalcGridCoord: igCoord    toMatrix: igInput];
	[self recalcGridCoord: igOldCoord toMatrix: igOldInput];

	return self;
   }


- ukz31Changed:sender
{
	/* read the new value */
	[self inputGridCoord: ukz31Coord inMatrix: ukz31Input];

	[ukz31Coord  convert: worldCoord];
	[self outputWorldCoord: worldCoord inMatrix: worldInput];

	/* update all the grid displays to match the new world Coord */
	[self recalcGridCoord: ukngCoord  toMatrix: ukngInput];
	[self recalcGridCoord: ukz30Coord toMatrix: ukz30Input];
	[self recalcGridCoord: igCoord    toMatrix: igInput];
	[self recalcGridCoord: igOldCoord toMatrix: igOldInput];

	return self;
   }

- igChanged:sender
{
	/* read the new value */
	[self inputGridCoord: igCoord inMatrix: igInput];

	[igCoord  convert: worldCoord];
	[self outputWorldCoord: worldCoord inMatrix: worldInput];

	/* update all the grid displays to match the new world Coord */
	[self recalcGridCoord: ukngCoord  toMatrix: ukngInput];
	[self recalcGridCoord: ukz30Coord toMatrix: ukz30Input];
	[self recalcGridCoord: ukz31Coord toMatrix: ukz31Input];
	[self recalcGridCoord: igOldCoord toMatrix: igOldInput];

	return self;
   }

- igOldChanged:sender
{
	/* read the new value */
	[self inputGridCoord: igOldCoord inMatrix: igOldInput];

	[igOldCoord  convert: worldCoord];
	[self outputWorldCoord: worldCoord inMatrix: worldInput];

	/* update all the grid displays to match the new world Coord */
	[self recalcGridCoord: ukngCoord  toMatrix: ukngInput];
	[self recalcGridCoord: ukz30Coord toMatrix: ukz30Input];
	[self recalcGridCoord: ukz31Coord toMatrix: ukz31Input];
	[self recalcGridCoord: igCoord    toMatrix: igInput];

	return self;
   }

@end
